﻿using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

public sealed class ObjectDumper
{
    public static void Write(object element, System.Xml.XmlTextWriter log)
    {
        ObjectDumper dumper = new ObjectDumper();
        dumper.writer = log;
        dumper.WriteObject(element);
    }

    private System.Xml.XmlTextWriter writer;

    private void Write(string s)
    {
        if (s != null)
            writer.WriteValue(s);
    }

    private void Begin(string name)
    {
        writer.WriteStartElement(name);
    }

    private void End()
    {
        writer.WriteEndElement();
    }

    private List<int> visited = new List<int>();

    private void WriteObject(object element)
    {
        int hash = element.GetHashCode();
        if (visited.Contains(hash))
            return;
        visited.Add(hash);
        string name = element.GetType().Name;
        Begin(name);
        if (element is ValueType || element is string)
        {
            WriteValue(element);
        }
        else
        {
            IEnumerable enumerableElement = element as IEnumerable;
            if (enumerableElement != null)
            {
                foreach (object item in enumerableElement)
                {
                    if (item != null)
                        WriteObject(item);
                }
            }
            else
            {
                MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
                foreach (MemberInfo m in members)
                {
                    if (m.Name == "Feed")
                        continue;
                    FieldInfo f = m as FieldInfo;
                    PropertyInfo p = m as PropertyInfo;
                    if (f != null || p != null)
                    {
                        Begin(m.Name);
                        Type t = f != null ? f.FieldType : p.PropertyType;
                        object value;
                        try
                        {
                            value = f != null ? f.GetValue(element) : p.GetValue(element, null);
                        }
                        catch(Exception e)
                        {
                            value = e.Message;
                        }
                        if (value == null || t.IsValueType || t == typeof(string))
                        {
                            WriteValue(value);
                        }
                        else
                        {
                            WriteObject(value);
                        }
                        End();
                    }
                }
            }
        }
        End();
    }

    private void WriteValue(object o)
    {
        if (o == null)
            Write("null");
        else if (o is DateTime)
            Write(((DateTime)o).ToLongTimeString());
        else if (o is ValueType)
            Write(o.ToString());
        else if (o is string)
            Write("\"" + o.ToString() + "\"");
        else
            WriteObject(o);
    }
}